package org.light.domain;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.apache.log4j.Logger;
import org.light.complexverb.AddUploadDomainField;
import org.light.complexverb.DomainFieldVerb;
import org.light.complexverb.UpdateUploadDomainField;
import org.light.core.PrismInterface;
import org.light.core.SpringMVCController;
import org.light.core.Verb;
import org.light.easyuilayouts.widgets.Nav;
import org.light.exception.ValidateException;
import org.light.generator.DBDefinitionGenerator;
import org.light.generator.MybatisDaoXmlDecorator;
import org.light.generator.NamedUtilMethodGenerator;
import org.light.layouts.EasyUIGridPagePI;
import org.light.layouts.EasyUIMtmPI;
import org.light.limitedverb.CountActiveRecords;
import org.light.limitedverb.CountAllPage;
import org.light.limitedverb.CountSearchByFieldsRecords;
import org.light.limitedverb.DaoOnlyVerb;
import org.light.limitedverb.NoControllerVerb;
import org.light.utils.StringUtil;
import org.light.verb.Activate;
import org.light.verb.ActivateAll;
import org.light.verb.Add;
import org.light.verb.Clone;
import org.light.verb.CloneAll;
import org.light.verb.Delete;
import org.light.verb.DeleteAll;
import org.light.verb.Export;
import org.light.verb.ExportPDF;
import org.light.verb.ExportWord;
import org.light.verb.FilterExcel;
import org.light.verb.FilterPDF;
import org.light.verb.FilterWord;
import org.light.verb.FindById;
import org.light.verb.FindByName;
import org.light.verb.ListActive;
import org.light.verb.ListAll;
import org.light.verb.ListAllByPage;
import org.light.verb.SearchByFields;
import org.light.verb.SearchByFieldsByPage;
import org.light.verb.SearchByName;
import org.light.verb.SoftDelete;
import org.light.verb.SoftDeleteAll;
import org.light.verb.Toggle;
import org.light.verb.ToggleOne;
import org.light.verb.Update;

import net.sf.json.JSONObject;

public class Prism implements Comparable<Prism> {
	protected static Logger logger = Logger.getLogger(Prism.class);
	protected long prismId;
	protected String standardName;
	protected long namingId;
	protected Naming naming;
	protected long domainClassId;
	protected Domain domain;
	protected long daoimplClassId;
	protected long serviceimplClassId;
	protected long daoId;
	protected Dao dao;
	protected DaoImpl daoimpl;
	protected long serviceId;
	protected Service service;
	protected ServiceImpl serviceimpl;
	protected String prismComment;
	protected List<Class> classes = new ArrayList<Class>();
	protected List<Util> utils = new ArrayList<Util>();
	protected List<SpringMVCController> controllers = new ArrayList<SpringMVCController>();
	protected String folderPath = "D:/JerryWork/Infinity/testFiles/";
	protected DBDefinitionGenerator dbDefinitionGenerator;
	protected Set<PrismInterface> pages = new TreeSet<PrismInterface>(new PrismInterfaceSerialComparator());
	protected String packageToken;
	protected TestSuite prismTestSuite;
	protected TestCase daoImplTestCase;
	protected TestCase serviceImplTestCase;
	protected List<Verb> verbs = new ArrayList<Verb>();
	protected List<NoControllerVerb> noControllerVerbs = new ArrayList<NoControllerVerb>();
	protected List<DaoOnlyVerb> daoOnlyVerbs = new ArrayList<DaoOnlyVerb>();
	protected MybatisDaoXmlDecorator mybatisDaoXmlDecorator;
	protected String label;
	protected Set<Pair> manyToManySlaveNames = new TreeSet<Pair>();
	protected Set<ManyToMany> manyToManies = new TreeSet<ManyToMany>();
	protected Set<Domain> projectDomains = new TreeSet<Domain>();
	protected String title = "";
	protected String subTitle = "";
	protected String footer = "";
	protected String crossOrigin = "";	
	protected SpringMVCController controller;
	protected String resolution = "low";
	protected Set<DomainFieldVerb> domianFieldVerbs = new TreeSet<>();
	protected Nav nav;
	protected String technicalStack = "sbmeu";
	protected String dbType = "MariaDB";
	
	public String getResolution() {
		return resolution;
	}

	public void setResolution(String resolution) {
		this.resolution = resolution;
	}

	public Prism() {
		super();
	}

	public SpringMVCController getController() {
		return controller;
	}

	public void setController(SpringMVCController controller) {
		this.controller = controller;
	}

	public MybatisDaoXmlDecorator getMybatisDaoXmlDecorator() {
		return mybatisDaoXmlDecorator;
	}

	public void setMybatisDaoXmlDecorator(MybatisDaoXmlDecorator mybatisDaoXmlDecorator) {
		this.mybatisDaoXmlDecorator = mybatisDaoXmlDecorator;
	}

	public List<SpringMVCController> getControllers() {
		return controllers;
	}

	public void setControllers(List<SpringMVCController> controllers) {
		this.controllers = controllers;
	}

	public List<NoControllerVerb> getNoControllerVerbs() {
		return noControllerVerbs;
	}

	public void setNoControllerVerbs(List<NoControllerVerb> noControllerVerbs) {
		this.noControllerVerbs = noControllerVerbs;
	}
	
	public void addNoControllerVerb(NoControllerVerb nv) {
		this.noControllerVerbs.add(nv);
	}
	
	public void removeNoControllerVerb(NoControllerVerb nv) throws Exception{
		if (nv!=null) {
			this.noControllerVerbs.remove(nv);
			service.removeMethod(nv.generateServiceMethodDefinition());
			serviceimpl.removeMethod(nv.generateServiceImplMethod());
			dao.removeMethod(nv.generateDaoMethodDefinition());
			daoimpl.removeMethod(nv.generateDaoImplMethod());
			if (getMybatisDaoXmlDecorator()!=null) getMybatisDaoXmlDecorator().removeDaoXmlMethod(nv.generateDaoImplMethod());
		}
	}

	public List<DaoOnlyVerb> getDaoOnlyVerbs() {
		return daoOnlyVerbs;
	}

	public void setDaoOnlyVerbs(List<DaoOnlyVerb> daoOnlyVerbs) {
		this.daoOnlyVerbs = daoOnlyVerbs;
	}

	public List<Util> getUtils() {
		return utils;
	}

	public void setUtils(List<Util> utils) {
		this.utils = utils;
	}

	public void addUtil(Util util) {
		this.utils.add(util);
	}

	public long getPrismId() {
		return prismId;
	}

	public List<Class> getClasses() {
		return classes;
	}

	public void setClasses(List<Class> classes) {
		this.classes = classes;
	}

	public void addClass(Class clazz) {
		this.classes.add(clazz);
	}

	public void setPrismId(long prismId) {
		this.prismId = prismId;
	}

	public String getStandardName() {
		return standardName;
	}

	public void setStandardName(String standardName) {
		this.standardName = standardName;
	}

	public long getNamingId() {
		return namingId;
	}

	public void setNamingId(long namingId) {
		this.namingId = namingId;
	}

	public Naming getNaming() {
		return naming;
	}

	public void setNaming(Naming naming) {
		this.naming = naming;
	}

	public long getDomainClassId() {
		return domainClassId;
	}

	public void setDomainClassId(long domainClassId) {
		this.domainClassId = domainClassId;
	}

	public Domain getDomain() {
		return domain;
	}

	public void setDomain(Domain domain) {
		this.domain = domain;
	}

	public long getDaoimplClassId() {
		return daoimplClassId;
	}

	public void setDaoimplClassId(long daoimplClassId) {
		this.daoimplClassId = daoimplClassId;
	}

	public DaoImpl getDaoimpl() {
		return this.daoimpl;
	}

	public void setDaoimpl(DaoImpl daoimpl) {
		this.daoimpl = daoimpl;
	}

	public long getServiceImplClassId() {
		return serviceimplClassId;
	}

	public void setServiceImplClassId(long serviceimplClassId) {
		this.serviceimplClassId = serviceimplClassId;
	}

	public ServiceImpl getServiceImpl() {
		return serviceimpl;
	}

	public void setServiceImpl(ServiceImpl serviceimpl) {
		this.serviceimpl = serviceimpl;
	}

	public long getDaoId() {
		return daoId;
	}

	public void setDaoId(long daoId) {
		this.daoId = daoId;
	}

	public Dao getDao() {
		return dao;
	}

	public void setDao(Dao dao) {
		this.dao = dao;
	}

	public long getServiceId() {
		return serviceId;
	}

	public void setServiceId(long serviceId) {
		this.serviceId = serviceId;
	}

	public Service getService() {
		return service;
	}

	public void setService(Service service) {
		this.service = service;
	}

	public String getPrismComment() {
		return prismComment;
	}

	public void setPrismComment(String prismComment) {
		this.prismComment = prismComment;
	}

	public void generatePrismFiles(Boolean ignoreWarning,Boolean genUi,Boolean genController,Boolean genService,Boolean genServiceImpl,Boolean genDao,Boolean genDaoImpl) throws ValidateException {
		ValidateInfo info = this.validate(ignoreWarning);
		if (info.success(ignoreWarning) == false) {
			ValidateException e = new ValidateException(info);
			throw e;
		}
		try {
			String srcfolderPath = folderPath;
			if (this.packageToken != null && !"".equals(this.packageToken)){
				srcfolderPath = folderPath + "src/main/java/" + packagetokenToFolder(this.packageToken);

				writeToFile(srcfolderPath +packagetokenToFolder(this.domain.getDomainSuffix())  +this.getDomain().getCapFirstDomainNameWithSuffix()+ ".java",
					this.getDomain().generateClassString());
			
				if (genDao && this.getDao() != null) {
					writeToFile(
							srcfolderPath + packagetokenToFolder(this.domain.getDaoSuffix()) + StringUtil.capFirst(this.getDomain().getStandardName()) + "Dao.java",
							this.getDao().generateDaoString());
				}
	
				if (genDaoImpl&&this.getDaoImpl() != null) {
					writeToFile(
							folderPath + "src/main/resources/mapper/" + StringUtil.capFirst(this.getDomain().getStandardName()) + "Dao.xml",
							this.mybatisDaoXmlDecorator.generateMybatisDaoXmlFileStr());
				}
	
				if (genService&&this.getService() != null) {
					writeToFile(srcfolderPath +  packagetokenToFolder(this.domain.getServiceSuffix())  + StringUtil.capFirst(this.getDomain().getStandardName())
							+ "Service.java", this.getService().generateServiceString());
				}
	
				if (genServiceImpl&&this.getServiceImpl() != null) {
					writeToFile(srcfolderPath + packagetokenToFolder(this.domain.getServiceimplSuffix()) + StringUtil.capFirst(this.getDomain().getStandardName())
							+ "ServiceImpl.java", this.getServiceImpl().generateServiceImplString());
				}
	
				if (genController&&this.controller != null) {
					writeToFile(srcfolderPath +  packagetokenToFolder(this.domain.getControllerSuffix())  + StringUtil.capFirst(this.domain.getCapFirstDomainName())
							+ this.domain.getControllerNamingSuffix()+".java", this.controller.generateControllerString());
				}
	
				if (genUi) {
					for (PrismInterface page : this.pages) {
						page.generatePIFiles(folderPath);
					}
	
					for (ManyToMany mtm : this.manyToManies) {
						EasyUIMtmPI mpage = mtm.getEuPI();
						mpage.setTechnicalStack(this.technicalStack);
						mpage.setTitles(this.getTitle(), this.getSubTitle(), this.getFooter());
						mpage.setNav(this.getNav());
						mpage.generatePIFiles(folderPath);
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	public void generateSMEUPrismFiles(Boolean ignoreWarning,Boolean genUi,Boolean genController,Boolean genService,Boolean genServiceImpl,Boolean genDao,Boolean genDaoImpl) throws ValidateException {
		ValidateInfo info = this.validate(ignoreWarning);
		if (info.success(ignoreWarning) == false) {
			ValidateException e = new ValidateException(info);
			throw e;
		}
		try {
			String projectFolderPath = folderPath.replace('\\', '/');
			String srcfolderPath = projectFolderPath;
			if (this.packageToken != null && !"".equals(this.packageToken)){
				srcfolderPath = folderPath + "src/" + packagetokenToFolder(this.packageToken);

				writeToFile(srcfolderPath + packagetokenToFolder(this.domain.getDomainSuffix())+"/"+this.domain.getCapFirstDomainNameWithSuffix()+ ".java",
					this.getDomain().generateClassString());
			
				if (genDao&&this.getDao() != null) {
					writeToFile(
							srcfolderPath + packagetokenToFolder(this.domain.getDaoSuffix())+"/" + StringUtil.capFirst(this.getDomain().getStandardName()) + "Dao.java",
							this.getDao().generateDaoString());
				}
	
				if (genDaoImpl&&this.getDaoImpl() != null) {
					writeToFile(
							srcfolderPath + packagetokenToFolder(this.domain.getDaoSuffix())+"/" +StringUtil.capFirst(this.getDomain().getStandardName()) + "Dao.xml",
							this.mybatisDaoXmlDecorator.generateMybatisDaoXmlFileStr());
				}
	
				if (genService&&this.getService() != null) {
					writeToFile(srcfolderPath + packagetokenToFolder(this.domain.getServiceSuffix())+"/"+StringUtil.capFirst(this.getDomain().getStandardName())
							+ "Service.java", this.getService().generateServiceString());
				}
	
				if (genServiceImpl&&this.getServiceImpl() != null) {
					writeToFile(srcfolderPath + packagetokenToFolder( this.domain.getServiceimplSuffix())+"/" + StringUtil.capFirst(this.getDomain().getStandardName())
							+ "ServiceImpl.java", this.getServiceImpl().generateServiceImplString());
				}
	
				if (genController&&this.controller != null) {
					writeToFile(srcfolderPath + packagetokenToFolder(this.domain.getControllerSuffix())+"/"+StringUtil.capFirst(this.domain.getCapFirstDomainName())
							+ this.domain.getControllerNamingSuffix()+".java", this.controller.generateControllerString());
				}
	
				if (genUi) {
					for (PrismInterface page : this.pages) {
						page.generatePIFiles(projectFolderPath);
					}
		
					for (ManyToMany mtm : this.manyToManies) {
						EasyUIMtmPI mPage = mtm.getEuPI();
						mPage.setTechnicalStack(this.technicalStack);
						mPage.setTitles(this.getTitle(), this.getSubTitle(), this.getFooter());
						mPage.setNav(this.getNav());
						mPage.generatePIFiles(projectFolderPath);
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public String getFolderPath() {
		return folderPath;
	}

	public void setFolderPath(String folderPath) {
		this.folderPath = folderPath;
	}

	public DaoImpl getDaoImpl() {
		return daoimpl;
	}

	public void setDaoImpl(DaoImpl daoImpl) {
		this.daoimpl = daoImpl;
	}

	public long getServiceimplClassId() {
		return serviceimplClassId;
	}

	public void setServiceimplClassId(long serviceimplClassId) {
		this.serviceimplClassId = serviceimplClassId;
	}

	public ServiceImpl getServiceimpl() {
		return serviceimpl;
	}

	public void setServiceimpl(ServiceImpl serviceimpl) {
		this.serviceimpl = serviceimpl;
	}

	public DBDefinitionGenerator getDbDefinitionGenerator() {
		return dbDefinitionGenerator;
	}

	public void setDbDefinitionGenerator(DBDefinitionGenerator dbDefinitionGenerator) {
		this.dbDefinitionGenerator = dbDefinitionGenerator;
	}

	public String getPackageToken() {
		return packageToken;
	}

	public void setPackageToken(String packagetoken) {
		if (packagetoken != null) {
			this.packageToken = packagetoken;
			if (this.dao != null)
				this.dao.setPackageToken(packagetoken);
			if (this.daoimpl != null)
				this.daoimpl.setPackageToken(packagetoken);
			if (this.serviceimpl != null)
				this.service.setPackageToken(packagetoken);
			if (this.serviceimpl != null)
				this.serviceimpl.setPackageToken(packagetoken);
			if (this.controller != null)
				this.controller.setPackageToken(packagetoken);
		}
	}

	public void generatePrismFromDomain(Boolean ignoreWarning) throws ValidateException, Exception {
		if (this.domain != null) {
			if (this.getPackageToken() != null) {
				this.domain.setPackageToken(packageToken);
			}
			
			this.domain.decorateCompareTo();

			this.dao = new Dao();
			this.dao.setDomain(this.domain);
			this.dao.setPackageToken(this.domain.getPackageToken());
			this.daoimpl = new DaoImpl();
			this.daoimpl.setPackageToken(this.domain.getPackageToken());
			this.daoimpl.setDomain(this.domain);
			this.daoimpl.setDao(this.dao);

			this.service = new Service();
			this.service.setDomain(this.domain);
			this.service.setPackageToken(this.domain.getPackageToken());
			this.serviceimpl = new ServiceImpl(this.domain);
			this.serviceimpl.setPackageToken(this.domain.getPackageToken());
			this.serviceimpl.getDao().addAnnotation("Autowired");
			Method daoSetter = NamedUtilMethodGenerator.generateSetter("dao",
					new Type(this.domain.getCapFirstDomainName() + "Dao"));
			this.serviceimpl.addMethod(daoSetter);
			this.serviceimpl.addClassImports("org.springframework.beans.factory.annotation.Autowired");
			this.serviceimpl.setDomain(this.domain);
			this.serviceimpl.setService(this.service);

			Verb listAll = new ListAll(this.domain);			
			Verb update = this.domain.hasDomainId() ?new Update(this.domain):null;
			Verb delete = this.domain.hasDomainId() ?new Delete(this.domain):null;
			Verb add = this.domain.hasDomainId() ?new Add(this.domain):null;
			Verb softdelete = this.domain.hasDomainId() && this.domain.hasActiveField() ?new SoftDelete(this.domain):null;
			Verb findbyid = this.domain.hasDomainId() ? new FindById(this.domain):null;
			Verb findbyname = this.domain.hasDomainName() ? new FindByName(this.domain):null;
			Verb searchbyname = this.domain.hasDomainName()?new SearchByName(this.domain):null;
			Verb listactive = this.domain.hasActiveField()?new ListActive(this.domain):null;
			Verb listAllByPage = new ListAllByPage(this.domain);
			Verb deleteAll = this.domain.hasDomainId() ?new DeleteAll(this.domain):null;
			Verb softDeleteAll = this.domain.hasDomainId() && this.domain.hasActiveField() ?new SoftDeleteAll(this.domain):null;
			Verb toggle = this.domain.hasDomainId() && this.domain.hasActiveField() ?new Toggle(this.domain):null;
			Verb toggleOne = this.domain.hasDomainId() && this.domain.hasActiveField() ?new ToggleOne(this.domain):null;
			Verb searchByFieldsByPage = new SearchByFieldsByPage(this.domain);
			Verb activate = this.domain.hasDomainId() && this.domain.hasActiveField() ?new Activate(this.domain):null;
			Verb activateAll = this.domain.hasDomainId() && this.domain.hasActiveField() ?new ActivateAll(this.domain):null;
			Verb export = new Export(this.domain);
			Verb exportPDF = new ExportPDF(this.domain);
			Verb exportWord = new ExportWord(this.domain);
			Verb searchByFields = new SearchByFields(this.domain);
			Verb filterExcel = new FilterExcel(this.domain);
			Verb filterPDF = new FilterPDF(this.domain);
			Verb filterWord = new FilterWord(this.domain);
			Verb clone	= this.domain.hasDomainId() ?new Clone(this.domain):null;
			Verb cloneAll = this.domain.hasDomainId()  ?new CloneAll(this.domain):null;
			
			CountAllPage countAllPage = new CountAllPage(this.domain);
			CountSearchByFieldsRecords countSearch = new CountSearchByFieldsRecords(this.domain);
			CountActiveRecords countActiveRecords = this.domain.hasDomainId() && this.domain.hasActiveField() ? new CountActiveRecords(this.domain):null;

			for (Field f:this.domain.getPlainFields()) {
				if (f.getFieldType().equalsIgnoreCase("image")) {
					domianFieldVerbs.add(new AddUploadDomainField(this.domain,f));
					domianFieldVerbs.add(new UpdateUploadDomainField(this.domain,f));
				}
			}
			this.addVerb(listAll);
			this.addVerb(update);
			this.addVerb(delete);
			this.addVerb(add);
			this.addVerb(softdelete);
			this.addVerb(findbyid);
			this.addVerb(findbyname);
			this.addVerb(searchbyname);
			this.addVerb(listactive);
			this.addVerb(listAllByPage);
			this.addVerb(deleteAll);
			this.addVerb(softDeleteAll);
			this.addVerb(toggle);
			this.addVerb(toggleOne);
			this.addVerb(searchByFieldsByPage);
			this.addVerb(activate);
			this.addVerb(activateAll);
			this.addVerb(export);
			this.addVerb(exportPDF);
			this.addVerb(exportWord);
			this.addVerb(searchByFields);
			this.addVerb(filterExcel);
			this.addVerb(filterPDF);
			this.addVerb(filterWord);
			this.addVerb(clone);
			this.addVerb(cloneAll);

			if (countAllPage !=null) this.noControllerVerbs.add(countAllPage);
			if (countSearch !=null) this.noControllerVerbs.add(countSearch);
			if (countActiveRecords !=null) this.noControllerVerbs.add(countActiveRecords);
			this.controller = new SpringMVCController(this.verbs, this.domain,ignoreWarning);
			this.controller.setPackageToken(this.packageToken);

			for (Verb v : this.verbs) {
				v.setDomain(domain);
				v.setDbType(this.dbType);
				service.addMethod(v.generateServiceMethodDefinition());
				serviceimpl.addMethod(v.generateServiceImplMethod());
				dao.addMethod(v.generateDaoMethodDefinition());
				daoimpl.addMethod(v.generateDaoImplMethod());
				controller.addMethod(v.generateControllerMethod());
			}

			for (NoControllerVerb nVerb : this.noControllerVerbs) {
				nVerb.setDomain(domain);
				service.addMethod(nVerb.generateServiceMethodDefinition());
				serviceimpl.addMethod(nVerb.generateServiceImplMethod());
				dao.addMethod(nVerb.generateDaoMethodDefinition());
				daoimpl.addMethod(nVerb.generateDaoImplMethod());
			}

			for (DaoOnlyVerb oVerb : this.daoOnlyVerbs) {
				oVerb.setDomain(domain);
				dao.addMethod(oVerb.generateDaoMethodDefinition());
				daoimpl.addMethod(oVerb.generateDaoImplMethod());
			}
			
			for (DomainFieldVerb dfv:domianFieldVerbs) {
				this.controller.addMethod(dfv.generateControllerMethod());
			}

			this.mybatisDaoXmlDecorator = new MybatisDaoXmlDecorator();
			this.mybatisDaoXmlDecorator.setDomain(this.getDomain());
			Set<Domain> resultMaps = new TreeSet<Domain>();
			resultMaps.add(this.domain);
			this.mybatisDaoXmlDecorator.setResultMaps(resultMaps);
			Set<Method> daoimplMethods = new TreeSet<Method>();
			for (Verb vb : this.verbs) {
				if (vb!=null && vb.generateDaoImplMethod()!=null){
					daoimplMethods.add(vb.generateDaoImplMethod());
				}
			}
			for (DaoOnlyVerb dovb : this.daoOnlyVerbs) {
				if (dovb!=null && dovb.generateDaoImplMethod()!=null){
					daoimplMethods.add(dovb.generateDaoImplMethod());
				}
			}
			for (NoControllerVerb ncvb : this.noControllerVerbs) {
				if (ncvb!=null && ncvb.generateDaoImplMethod()!=null){
					daoimplMethods.add(ncvb.generateDaoImplMethod());
				}
			}
			this.mybatisDaoXmlDecorator.setDaoXmlMethods(daoimplMethods);

			EasyUIGridPagePI easyui = new EasyUIGridPagePI(this.domain);
			easyui.setTitles(this.getTitle(),this.getSubTitle(),this.getFooter());
			easyui.setDomain(this.domain);
			easyui.setTechnicalStack(this.technicalStack);
			this.addPage(easyui);

			if (this.domain.manyToManies != null && this.domain.manyToManies.size() > 0) {
				for (ManyToMany mtm : this.domain.manyToManies) {
					String slaveName = mtm.getManyToManySalveName();
					String masterName = this.domain.getStandardName();
					if (setContainsDomain(this.projectDomains, masterName)
							&& setContainsDomain(this.projectDomains, slaveName)) {
						Domain tempo = lookupDoaminInSet(this.projectDomains, slaveName);
						Domain myslave = tempo==null?null:(Domain)tempo.deepClone();
						if (myslave == null) continue;
						if (!StringUtil.isBlank(mtm.getSlaveAlias())){
							myslave.setAlias(mtm.getSlaveAlias());
							myslave.setAliasLabel(mtm.getSlaveAliasLabel());
						}
						ManyToMany mymtm = new ManyToMany(lookupDoaminInSet(this.projectDomains, masterName),
								myslave,mtm.getMasterValue(),mtm.getValues());	
						mymtm.setSlaveAlias(myslave.getAlias());
						mymtm.setSlaveAliasLabel(mtm.getSlaveAliasLabel());
						mymtm.setValues(mtm.getValues());
						this.manyToManies.add(mymtm);
						logger.debug("JerryDebug:"+mymtm+":Master:"+masterName+":"+myslave.getAlias()+"");
					} else {
						ValidateInfo validateInfo = new ValidateInfo();
						validateInfo.addCompileError("棱柱" + this.getText() + "多对多设置有误。");
						ValidateException em = new ValidateException(validateInfo);
						throw em;
					}
				}
			}
			for (ManyToMany mtm : this.manyToManies) {
				mtm.setTitle(this.title);
				mtm.setSubTitle(this.subTitle);
				mtm.setFooter(this.footer);
				mtm.setCrossOrigin(this.crossOrigin);
				this.service.addMethod(mtm.getAssign().generateServiceMethodDefinition());
				this.serviceimpl.addMethod(mtm.getAssign().generateServiceImplMethod());
				this.dao.addMethod(mtm.getAssign().generateDaoMethodDefinition());
				this.daoimpl.addMethod(mtm.getAssign().generateDaoImplMethod());
				this.mybatisDaoXmlDecorator.addDaoXmlMethod(mtm.getAssign().generateDaoImplMethod());
				this.controller.addMethod(mtm.getAssign().generateControllerMethod());

				this.service.addMethod(mtm.getRevoke().generateServiceMethodDefinition());
				this.serviceimpl.addMethod(mtm.getRevoke().generateServiceImplMethod());
				this.dao.addMethod(mtm.getRevoke().generateDaoMethodDefinition());
				this.daoimpl.addMethod(mtm.getRevoke().generateDaoImplMethod());
				this.mybatisDaoXmlDecorator.addDaoXmlMethod(mtm.getRevoke().generateDaoImplMethod());
				this.controller.addMethod(mtm.getRevoke().generateControllerMethod());

				this.service.addMethod(mtm.getListMyActive().generateServiceMethodDefinition());
				this.serviceimpl.addMethod(mtm.getListMyActive().generateServiceImplMethod());
				this.dao.addMethod(mtm.getListMyActive().generateDaoMethodDefinition());
				this.daoimpl.addMethod(mtm.getListMyActive().generateDaoImplMethod());
				this.mybatisDaoXmlDecorator.addResultMap(mtm.getSlave());
				this.mybatisDaoXmlDecorator.addDaoXmlMethod(mtm.getListMyActive().generateDaoImplMethod());
				this.controller.addMethod(mtm.getListMyActive().generateControllerMethod());

				this.service.addMethod(mtm.getListMyAvailableActive().generateServiceMethodDefinition());
				this.serviceimpl.addMethod(mtm.getListMyAvailableActive().generateServiceImplMethod());
				this.dao.addMethod(mtm.getListMyAvailableActive().generateDaoMethodDefinition());
				this.daoimpl.addMethod(mtm.getListMyAvailableActive().generateDaoImplMethod());
				this.mybatisDaoXmlDecorator.addDaoXmlMethod(mtm.getListMyAvailableActive().generateDaoImplMethod());
				this.controller.addMethod(mtm.getListMyAvailableActive().generateControllerMethod());
				//mtm.slave.decorateCompareTo();
				
				Service slaveService = new Service();
				slaveService.setDomain(mtm.slave);
				slaveService.addAnnotation("Autowired");
				slaveService.setStandardName(mtm.slave.getCapFirstDomainName() + "Service");
				
				Method slaveServiceSetter = NamedUtilMethodGenerator.generateSetter(mtm.slave.getLowerFirstDomainName()+"Service",
						new Type(mtm.slave.getCapFirstDomainName() + "Service",mtm.getSlave().getPackageToken()+"."+mtm.slave.getServiceSuffix()+"."+mtm.slave.getCapFirstDomainName() + "Service"));
				this.serviceimpl.addMethod(slaveServiceSetter);
				this.serviceimpl.addOtherService(slaveService);
			}
		}
	}
	
	public void generatePgPrismFromDomain(Boolean ignoreWarning) throws ValidateException, Exception {
		if (this.domain != null) {
			if (this.getPackageToken() != null) {
				this.domain.setPackageToken(packageToken);
			}
			
			this.domain.decorateCompareTo();

			this.dao = new Dao();
			this.dao.setDomain(this.domain);
			this.dao.setPackageToken(this.domain.getPackageToken());
			this.daoimpl = new DaoImpl();
			this.daoimpl.setPackageToken(this.domain.getPackageToken());
			this.daoimpl.setDomain(this.domain);
			this.daoimpl.setDao(this.dao);

			this.service = new Service();
			this.service.setDomain(this.domain);
			this.service.setPackageToken(this.domain.getPackageToken());
			this.serviceimpl = new ServiceImpl(this.domain);
			this.serviceimpl.setPackageToken(this.domain.getPackageToken());
			this.serviceimpl.getDao().addAnnotation("Autowired");
			Method daoSetter = NamedUtilMethodGenerator.generateSetter("dao",
					new Type(this.domain.getCapFirstDomainName() + "Dao"));
			this.serviceimpl.addMethod(daoSetter);
			this.serviceimpl.addClassImports("org.springframework.beans.factory.annotation.Autowired");
			this.serviceimpl.setDomain(this.domain);
			this.serviceimpl.setService(this.service);

			Verb listAll = new org.light.pgsql.verb.ListAll(this.domain);			
			Verb update = this.domain.hasDomainId() ?new Update(this.domain):null;
			Verb delete = this.domain.hasDomainId() ?new Delete(this.domain):null;
			Verb add = this.domain.hasDomainId() ?new Add(this.domain):null;
			Verb softdelete = this.domain.hasDomainId() && this.domain.hasActiveField() ?new SoftDelete(this.domain):null;
			Verb findbyid = this.domain.hasDomainId() ? new FindById(this.domain):null;
			Verb findbyname = this.domain.hasDomainName() ? new FindByName(this.domain):null;
			Verb searchbyname = this.domain.hasDomainName()?new org.light.pgsql.verb.SearchByName(this.domain):null;
			Verb listactive = this.domain.hasActiveField()?new ListActive(this.domain):null;
			Verb listAllByPage = new ListAllByPage(this.domain);
			Verb deleteAll = this.domain.hasDomainId() ?new DeleteAll(this.domain):null;
			Verb softDeleteAll = this.domain.hasDomainId() && this.domain.hasActiveField() ?new SoftDeleteAll(this.domain):null;
			Verb toggle = this.domain.hasDomainId() && this.domain.hasActiveField() ?new Toggle(this.domain):null;
			Verb toggleOne = this.domain.hasDomainId() && this.domain.hasActiveField() ?new ToggleOne(this.domain):null;
			Verb searchByFieldsByPage = new org.light.pgsql.verb.SearchByFieldsByPage(this.domain);
			Verb activate = this.domain.hasDomainId() && this.domain.hasActiveField() ?new Activate(this.domain):null;
			Verb activateAll = this.domain.hasDomainId() && this.domain.hasActiveField() ?new ActivateAll(this.domain):null;
			Verb export = new Export(this.domain);
			Verb exportPDF = new ExportPDF(this.domain);
			Verb exportWord = new ExportWord(this.domain);
			Verb searchByFields = new org.light.pgsql.verb.SearchByFields(this.domain);
			Verb filterExcel = new FilterExcel(this.domain);
			Verb filterPDF = new FilterPDF(this.domain);
			Verb filterWord = new FilterWord(this.domain);
			Verb clone	= this.domain.hasDomainId() ?new Clone(this.domain):null;
			Verb cloneAll = this.domain.hasDomainId()  ?new CloneAll(this.domain):null;
			
			CountAllPage countAllPage = new CountAllPage(this.domain);
			org.light.pgsql.verb.CountSearchByFieldsRecords countSearch = new org.light.pgsql.verb.CountSearchByFieldsRecords(this.domain);
			CountActiveRecords countActiveRecords = this.domain.hasDomainId() && this.domain.hasActiveField() ? new CountActiveRecords(this.domain):null;

			for (Field f:this.domain.getPlainFields()) {
				if (f.getFieldType().equalsIgnoreCase("image")) {
					domianFieldVerbs.add(new AddUploadDomainField(this.domain,f));
					domianFieldVerbs.add(new UpdateUploadDomainField(this.domain,f));
				}
			}
			
			this.addVerb(listAll);
			this.addVerb(update);
			this.addVerb(delete);
			this.addVerb(add);
			this.addVerb(softdelete);
			this.addVerb(findbyid);
			this.addVerb(findbyname);
			this.addVerb(searchbyname);
			this.addVerb(listactive);
			this.addVerb(listAllByPage);
			this.addVerb(deleteAll);
			this.addVerb(softDeleteAll);
			this.addVerb(toggle);
			this.addVerb(toggleOne);
			this.addVerb(searchByFieldsByPage);
			this.addVerb(activate);
			this.addVerb(activateAll);
			this.addVerb(export);
			this.addVerb(exportPDF);
			this.addVerb(exportWord);
			this.addVerb(searchByFields);
			this.addVerb(filterExcel);
			this.addVerb(filterPDF);
			this.addVerb(filterWord);
			this.addVerb(clone);
			this.addVerb(cloneAll);

			if (countAllPage !=null) this.noControllerVerbs.add(countAllPage);
			if (countSearch !=null) this.noControllerVerbs.add(countSearch);
			if (countActiveRecords !=null) this.noControllerVerbs.add(countActiveRecords);
			this.controller = new SpringMVCController(this.verbs, this.domain,ignoreWarning);
			this.controller.setPackageToken(this.packageToken);

			for (Verb v : this.verbs) {
				v.setDomain(domain);
				service.addMethod(v.generateServiceMethodDefinition());
				serviceimpl.addMethod(v.generateServiceImplMethod());
				dao.addMethod(v.generateDaoMethodDefinition());
				daoimpl.addMethod(v.generateDaoImplMethod());
				controller.addMethod(v.generateControllerMethod());
			}

			for (NoControllerVerb nVerb : this.noControllerVerbs) {
				nVerb.setDomain(domain);
				service.addMethod(nVerb.generateServiceMethodDefinition());
				serviceimpl.addMethod(nVerb.generateServiceImplMethod());
				dao.addMethod(nVerb.generateDaoMethodDefinition());
				daoimpl.addMethod(nVerb.generateDaoImplMethod());
			}

			for (DaoOnlyVerb oVerb : this.daoOnlyVerbs) {
				oVerb.setDomain(domain);
				dao.addMethod(oVerb.generateDaoMethodDefinition());
				daoimpl.addMethod(oVerb.generateDaoImplMethod());
			}
			
			for (DomainFieldVerb dfv:domianFieldVerbs) {
				this.controller.addMethod(dfv.generateControllerMethod());
			}

			this.mybatisDaoXmlDecorator = new MybatisDaoXmlDecorator();
			this.mybatisDaoXmlDecorator.setDomain(this.getDomain());
			Set<Domain> resultMaps = new TreeSet<Domain>();
			resultMaps.add(this.domain);
			this.mybatisDaoXmlDecorator.setResultMaps(resultMaps);
			Set<Method> daoimplMethods = new TreeSet<Method>();
			for (Verb vb : this.verbs) {
				if (vb!=null && vb.generateDaoImplMethod()!=null){
					daoimplMethods.add(vb.generateDaoImplMethod());
				}
			}
			for (DaoOnlyVerb dovb : this.daoOnlyVerbs) {
				if (dovb!=null && dovb.generateDaoImplMethod()!=null){
					daoimplMethods.add(dovb.generateDaoImplMethod());
				}
			}
			for (NoControllerVerb ncvb : this.noControllerVerbs) {
				if (ncvb!=null && ncvb.generateDaoImplMethod()!=null){
					daoimplMethods.add(ncvb.generateDaoImplMethod());
				}
			}
			this.mybatisDaoXmlDecorator.setDaoXmlMethods(daoimplMethods);

			EasyUIGridPagePI easyui = new EasyUIGridPagePI(this.domain);
			easyui.setTitles(this.getTitle(), this.getSubTitle(), this.getFooter());
			easyui.setTechnicalStack(this.technicalStack);
			this.addPage(easyui);

			if (this.domain.manyToManies != null && this.domain.manyToManies.size() > 0) {
				for (ManyToMany mtm : this.domain.manyToManies) {
					String slaveName = mtm.getManyToManySalveName();
					String masterName = this.domain.getStandardName();
					if (setContainsDomain(this.projectDomains, masterName)
							&& setContainsDomain(this.projectDomains, slaveName)) {
						Domain tempo = lookupDoaminInSet(this.projectDomains, slaveName);
						Domain myslave = tempo==null?null:(Domain)tempo.deepClone();
						if (myslave == null) continue;
						if (!StringUtil.isBlank(mtm.getSlaveAlias())){
							myslave.setAlias(mtm.getSlaveAlias());
							myslave.setAliasLabel(mtm.getSlaveAliasLabel());
						}
						ManyToMany mymtm = new ManyToMany(lookupDoaminInSet(this.projectDomains, masterName),
								myslave,mtm.getMasterValue(),mtm.getValues());	
						mymtm.setSlaveAlias(myslave.getAlias());
						mymtm.setSlaveAliasLabel(mtm.getSlaveAliasLabel());
						mymtm.setValues(mtm.getValues());
						this.manyToManies.add(mymtm);
						logger.debug("JerryDebug:"+mymtm+":Master:"+masterName+":"+myslave.getAlias()+"");
					} else {
						ValidateInfo validateInfo = new ValidateInfo();
						validateInfo.addCompileError("棱柱" + this.getText() + "多对多设置有误。");
						ValidateException em = new ValidateException(validateInfo);
						throw em;
					}
				}
			}
			for (ManyToMany mtm : this.manyToManies) {
				mtm.setTitle(this.title);
				mtm.setSubTitle(this.subTitle);
				mtm.setFooter(this.footer);
				mtm.setCrossOrigin(this.crossOrigin);
				this.service.addMethod(mtm.getAssign().generateServiceMethodDefinition());
				this.serviceimpl.addMethod(mtm.getAssign().generateServiceImplMethod());
				this.dao.addMethod(mtm.getAssign().generateDaoMethodDefinition());
				this.daoimpl.addMethod(mtm.getAssign().generateDaoImplMethod());
				this.mybatisDaoXmlDecorator.addDaoXmlMethod(mtm.getAssign().generateDaoImplMethod());
				this.controller.addMethod(mtm.getAssign().generateControllerMethod());

				this.service.addMethod(mtm.getRevoke().generateServiceMethodDefinition());
				this.serviceimpl.addMethod(mtm.getRevoke().generateServiceImplMethod());
				this.dao.addMethod(mtm.getRevoke().generateDaoMethodDefinition());
				this.daoimpl.addMethod(mtm.getRevoke().generateDaoImplMethod());
				this.mybatisDaoXmlDecorator.addDaoXmlMethod(mtm.getRevoke().generateDaoImplMethod());
				this.controller.addMethod(mtm.getRevoke().generateControllerMethod());

				this.service.addMethod(mtm.getListMyActive().generateServiceMethodDefinition());
				this.serviceimpl.addMethod(mtm.getListMyActive().generateServiceImplMethod());
				this.dao.addMethod(mtm.getListMyActive().generateDaoMethodDefinition());
				this.daoimpl.addMethod(mtm.getListMyActive().generateDaoImplMethod());
				this.mybatisDaoXmlDecorator.addResultMap(mtm.getSlave());
				this.mybatisDaoXmlDecorator.addDaoXmlMethod(mtm.getListMyActive().generateDaoImplMethod());
				this.controller.addMethod(mtm.getListMyActive().generateControllerMethod());

				this.service.addMethod(mtm.getListMyAvailableActive().generateServiceMethodDefinition());
				this.serviceimpl.addMethod(mtm.getListMyAvailableActive().generateServiceImplMethod());
				this.dao.addMethod(mtm.getListMyAvailableActive().generateDaoMethodDefinition());
				this.daoimpl.addMethod(mtm.getListMyAvailableActive().generateDaoImplMethod());
				this.mybatisDaoXmlDecorator.addDaoXmlMethod(mtm.getListMyAvailableActive().generateDaoImplMethod());
				this.controller.addMethod(mtm.getListMyAvailableActive().generateControllerMethod());
				//mtm.slave.decorateCompareTo();
				
				Service slaveService = new Service();
				slaveService.setDomain(mtm.slave);
				slaveService.addAnnotation("Autowired");
				slaveService.setStandardName(mtm.slave.getCapFirstDomainName() + "Service");
				
				Method slaveServiceSetter = NamedUtilMethodGenerator.generateSetter(mtm.slave.getLowerFirstDomainName()+"Service",
						new Type(mtm.slave.getCapFirstDomainName() + "Service",mtm.getSlave().getPackageToken()+"."+mtm.slave.getServiceSuffix()+"."+mtm.slave.getCapFirstDomainName() + "Service"));
				this.serviceimpl.addMethod(slaveServiceSetter);
				this.serviceimpl.addOtherService(slaveService);
			}
		}
	}

	protected Boolean setContainsDomain(Set<Domain> set, String domainName) {
		for (Domain d : set) {
			if (d.getStandardName().equals(domainName))
				return true;
		}
		return false;
	}

	protected Domain lookupDoaminInSet(Set<Domain> set, String domainName) {
		for (Domain d : set) {
			if (d.getStandardName().equals(domainName)&&!d.isLegacy())
				return d;
		}
		return null;
	}

	public static String packagetokenToFolder(String packageToken) {
		String folder = packageToken.replace('.', '/');
		folder += "/";
		return folder;
	}

	public static String folderToPackageToken(String folder) {
		String packagetoken = folder.replace('/', '.');
		if (packagetoken.charAt(packagetoken.length() - 1) == '.')
			packagetoken = packagetoken.substring(0, packagetoken.length() - 1);
		return packagetoken;
	}

	public TestSuite getPrismTestSuite() {
		return prismTestSuite;
	}

	public void setPrismTestSuite(TestSuite prismTestSuite) {
		this.prismTestSuite = prismTestSuite;
	}

	public TestCase getDaoImplTestCase() {
		return daoImplTestCase;
	}

	public void setDaoImplTestCase(TestCase daoImplTestCase) {
		this.daoImplTestCase = daoImplTestCase;
	}

	public TestCase getServiceImplTestCase() {
		return serviceImplTestCase;
	}

	public void setServiceImplTestCase(TestCase serviceImplTestCase) {
		this.serviceImplTestCase = serviceImplTestCase;
	}

	public ValidateInfo validate(Boolean ignoreWarning) {
		List<ValidateInfo> vl = new ArrayList<ValidateInfo>();
		if (this.getDomain() == null) return ValidateInfo.mergeValidateInfo(vl,ignoreWarning);
		ValidateInfo info = this.getDomain().validate();
		vl.add(info);
		return ValidateInfo.mergeValidateInfo(vl,ignoreWarning);
	}

	public void expandPackageToken() {
		if (this.packageToken != null && !"".equals(this.packageToken)) {
			if (this.domain != null)
				this.domain.setPackageToken(this.packageToken);
			if (this.dao != null)
				this.dao.setPackageToken(this.packageToken);
			if (this.daoimpl != null)
				this.daoimpl.setPackageToken(this.packageToken);
			if (this.service != null)
				this.service.setPackageToken(this.packageToken);
			if (this.serviceimpl != null)
				this.serviceimpl.setPackageToken(this.packageToken);

			for (Class c : this.classes) {
				c.setPackageToken(this.packageToken);
			}

			if (this.prismTestSuite != null)
				this.prismTestSuite.setPackageToken(this.packageToken);
			if (this.daoImplTestCase != null)
				this.daoImplTestCase.setPackageToken(this.packageToken);
			if (this.serviceImplTestCase != null)
				this.serviceImplTestCase.setPackageToken(this.packageToken);
		}
	}

	@Override
	public int compareTo(Prism o) {
		String myName = this.getStandardName();
		String otherName = o.getStandardName();
		if (StringUtil.isBlank(myName)) myName = "";
		if (StringUtil.isBlank(otherName)) otherName = "";
		return myName.compareTo(otherName);
	}

	@Override
	public boolean equals(Object o) {
		return (this.compareTo((Prism) o) == 0);
	}

	public List<Verb> getVerbs() {
		return verbs;
	}

	public void setVerbs(List<Verb> verbs) {
		this.verbs = verbs;
	}

	public void addVerb(Verb verb) {
		if (verb != null) this.verbs.add(verb);
	}
	
	public void removeVerb(Verb verb) throws Exception{
		if (verb != null) {
			this.verbs.remove(verb);
			service.removeMethod(verb.generateServiceMethodDefinition());
			serviceimpl.removeMethod(verb.generateServiceImplMethod());
			dao.removeMethod(verb.generateDaoMethodDefinition());
			daoimpl.removeMethod(verb.generateDaoImplMethod());
			controller.removeMethod(verb.generateControllerMethod());
			if (getMybatisDaoXmlDecorator()!=null) getMybatisDaoXmlDecorator().removeDaoXmlMethod(verb.generateDaoImplMethod());
		}
	}

	public void writeToFile(String filePath, String content) throws Exception {
		File f = new File(filePath);
		if (!f.getParentFile().exists()) {
			f.getParentFile().mkdirs();
		}
		f.createNewFile();
		try (Writer fw = new BufferedWriter(
				new OutputStreamWriter(new FileOutputStream(f.getAbsolutePath()), "UTF-8"))) {
			fw.write(content, 0, content.length());
		}
	}

	public String getLabel() {
		return label;
	}

	public void setLabel(String label) {
		this.label = label;
	}

	public String getText() {
		if (this.label != null && !this.label.equals(""))
			return this.label;
		else
			return this.standardName;
	}

	public Set<Domain> getProjectDomains() {
		return projectDomains;
	}

	public void setProjectDomains(Set<Domain> projectDomains) {
		this.projectDomains = projectDomains;
	}
	
	public String toString(){
		return JSONObject.fromObject(this).toString();
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getSubTitle() {
		return subTitle;
	}

	public void setSubTitle(String subTitle) {
		this.subTitle = subTitle;
	}

	public String getFooter() {
		return footer;
	}

	public void setFooter(String footer) {
		this.footer = footer;
	}

	public String getCrossOrigin() {
		return crossOrigin;
	}

	public void setCrossOrigin(String crossOrigin) {
		this.crossOrigin = crossOrigin;
	}

	public Set<Pair> getManyToManySlaveNames() {
		return manyToManySlaveNames;
	}

	public void setManyToManySlaveNames(Set<Pair> manyToManySlaveNames) {
		this.manyToManySlaveNames = manyToManySlaveNames;
	}

	public Set<ManyToMany> getManyToManies() {
		return manyToManies;
	}

	public void setManyToManies(Set<ManyToMany> manyToManies) {
		this.manyToManies = manyToManies;
	}

	public Set<PrismInterface> getPages() {
		return pages;
	}

	public void setPages(Set<PrismInterface> pages) {
		this.pages = pages;
	}
	
	public void addPage(PrismInterface  page) {
		long serial = 0L;
		for (PrismInterface pi:this.pages) {
			if (pi.getSerial()>serial) serial = pi.getSerial();
		}
		serial += 1000L;
		page.setSerial(serial);
		this.pages.add(page);
	}

	public Set<DomainFieldVerb> getDomianFieldVerbs() {
		return domianFieldVerbs;
	}

	public void setDomianFieldVerbs(Set<DomainFieldVerb> domianFieldVerbs) {
		this.domianFieldVerbs = domianFieldVerbs;
	}
	
	public void addDomianFieldVerb(DomainFieldVerb domianFieldVerb) {
		this.domianFieldVerbs.add(domianFieldVerb);
	}

	public Nav getNav() {
		return nav;
	}

	public void setNav(Nav nav) {
		this.nav = nav;
	}

	public String getTechnicalStack() {
		return technicalStack;
	}

	public void setTechnicalStack(String technicalStack) {
		this.technicalStack = technicalStack;
	}

	public String getDbType() {
		return dbType;
	}

	public void setDbType(String dbType) {
		this.dbType = dbType;
	}
}
